/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package beans.util;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.codec.Base64.OutputStream;
import db.entities.Examination;
import db.entities.Medic;
import db.entities.Patient;
import db.entities.Referenze;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import mail.Sender;
import org.richfaces.model.DataProvider;
import org.richfaces.model.ExtendedTableDataModel;
import org.richfaces.model.selection.SimpleSelection;

/**
 *
 * @author guybrush
 */
public class ExtendedDataTableBean extends Medic {

    //context Path
    String contPdfPath = "";
    
    //google key
    private final String GKey = "AIzaSyDAFC0glGjr201lq1Mnhqk-fmWj1cRcimU";
    
    //opzioni google
    private final int DefGZoomCity = 12;
    private int gzoom = 1;
    
    //opzioni e modello di selezione tabelle
    private Boolean performedF = false;
    private String selectionMode = "single";
    private SimpleSelection selectionPat = null,
                            selectionExam = null;
    private ExtendedTableDataModel<Patient> PatsDataModel = null;
    private ExtendedTableDataModel<Examination> ExamsDataModel = null;
    private List<Patient> selectedPats = new ArrayList<Patient>(),
                          patients = null;
    private List<Examination> examinations = null,
                              selectedExam = new ArrayList<Examination>();
       
    public ExtendedDataTableBean() {
    }
    public ExtendedDataTableBean(Integer id, String nome, String cognome, String username, String password)
    {
        setId(id);
        setNome(nome);
        setCognome(cognome);
        setUsername(username);
        setPassword(password);
    }
    
    //getter and setter
    public String getGKey()
    { return GKey; }

    public List<Patient> getSelectedPats() {
        return selectedPats;
    }

    public List<Examination> getSelectedExam() {
        return selectedExam;
    }
    
    public Patient getSingleSelectedPat()
    { 
        Iterator<Patient> it = selectedPats.iterator();
        if (it.hasNext()) return it.next();
        return new Patient();
    }
    
    public String getLongSingSelctedPat()
    {
        Patient tmp = getSingleSelectedPat();
        if (tmp.getId() == -1) return "0.0";
        
        return tmp.getLongitudine().toString();
    }
    
    public String getLatSingSelctedPat()
    {
        Patient tmp = getSingleSelectedPat();
        if (tmp.getId() == -1) return "0.0";
        
        return tmp.getLatitudine().toString();
    }
    
    public Boolean getNewButtonDisable()
    {
        return getSingleSelectedPat().getId() == -1;
    }
    
    public Examination getSingleSelectedExam()
    {
        Iterator<Examination> it = selectedExam.iterator();
        if (it.hasNext()) return it.next();
        return new Examination();
    }
    
    public Boolean getUpdatePatButtonDisable()
    {
        return !(getSingleSelectedPat().getId() != -1);
    }
    
    public Boolean getUpdateDeleteButtonDisable()
    {
        Examination tmp = getSingleSelectedExam();
        return !(tmp.getId() != null && tmp.getEffettuata() == false);
    }

    public List<Examination> getExaminations()
    {
        //istanzio
        if (examinations == null) examinations = new ArrayList<Examination>();
        if (getSelectedPats() != null && getSelectedPats().size() > 0)
        {
            //pulisco da risultati precedenti
            examinations.clear();
            EntityManagerFactory emf = Persistence.createEntityManagerFactory("PortaleVisitePU");
            EntityManager em = emf.createEntityManager();
            //per ogni paziente selezionato aggiungo i relativi esami
            for (Patient p : selectedPats)
                examinations.addAll(em.createNamedQuery("Examination.findByPatId", Examination.class)
                        .setParameter("id", p.getId()).getResultList());
        }
        else //altrimenti ritorno array vuoto
            return new ArrayList<Examination>();
        
        return examinations;
    }
    
    public List<Examination> getWaitingExaminations()
    {
        if (examinations == null) examinations = new ArrayList<Examination>();
        examinations.clear();
        
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PortaleVisitePU");
        EntityManager em = emf.createEntityManager();
        
        return (examinations = em.createNamedQuery("Examination.findWaitingExamination", Examination.class)
                    .setParameter("id", getId()).getResultList());
    }

    public void setExaminations(List<Examination> examinations) {
        this.examinations = examinations;
    }

    public void setSelectedPats(List<Patient> selectedPats) {
        this.selectedPats = selectedPats;
    }

    public String getSelectionMode() {
        return selectionMode;
    }

    public void setSelectionMode(String selectionMode) {
        this.selectionMode = selectionMode;
    }
    
    public void setSelectionPat(SimpleSelection selection) {
        this.selectionPat = selection; invalidExamsQueue();
    }
    
    public SimpleSelection getSelectionPat()
    { return selectionPat; }

    public SimpleSelection getSelectionExam() {
        return selectionExam;
    }

    public void setSelectionExam(SimpleSelection selectionExam) {
        this.selectionExam = selectionExam;
    }

    public Boolean getPerformedF() {
        return performedF;
    }

    public void setPerformedF(Boolean performedF) {
        this.performedF = performedF;
    }

    public ExtendedTableDataModel<Patient> getPatsDataModel()
    {
        if (patients == null) getPatientsList();
        if (PatsDataModel == null) 
        {
            PatsDataModel = new ExtendedTableDataModel<Patient>(new DataProvider<Patient>() {

                @Override
                public int getRowCount() { return patients.size(); }

                @Override
                public List<Patient> getItemsByRange(int i, int i1) { return patients.subList(i, i1); }

                @Override
                public Patient getItemByKey(Object key) 
                {
                    for(Patient p : patients)
                        if(key.equals(getKey(p)))
                            return p;
                    
                    return null;
                }
                
                @Override
                public Object getKey(Patient p) { return p.getId(); }
            });
        }

        return PatsDataModel;
    }
    
    public ExtendedTableDataModel<Patient> getWaitingPatsDataModel()
    {
        if (patients == null) getWaitedPatientsList();
        if (PatsDataModel == null) 
        {
            PatsDataModel = new ExtendedTableDataModel<Patient>(new DataProvider<Patient>() {

                @Override
                public int getRowCount() { return patients.size(); }

                @Override
                public List<Patient> getItemsByRange(int i, int i1) { return patients.subList(i, i1); }

                @Override
                public Patient getItemByKey(Object key) 
                {
                    for(Patient p : patients)
                        if(key.equals(getKey(p)))
                            return p;
                    
                    return null;
                }

                @Override
                public Object getKey(Patient p) { return p.getId(); }
            });
        }
            
        return PatsDataModel;
    }
    
    public ExtendedTableDataModel<Examination> getExaminationsDataModel()
    {
        if (examinations == null) getExaminations();
        if (ExamsDataModel == null)
        {
            ExamsDataModel = new ExtendedTableDataModel<Examination>(new DataProvider<Examination>() {

                @Override
                public int getRowCount() { return examinations.size(); }

                @Override
                public List<Examination> getItemsByRange(int i, int i1) { return examinations.subList(i, i1); }

                @Override
                public Examination getItemByKey(Object key) 
                {
                    for (Examination e : examinations)
                        if (key.equals(getKey(e)))
                            return e;

                    return null;
                }

                @Override
                public Object getKey(Examination e) { return e.getId(); }
            });
        }
                
        return ExamsDataModel;
    }
    
    public ExtendedTableDataModel<Examination> getWaitingExaminationsDataModel()
    {
        if (examinations == null) getWaitingExaminations();
        if (ExamsDataModel == null)
        {
            ExamsDataModel = new ExtendedTableDataModel<Examination>(new DataProvider<Examination>() {

                @Override
                public int getRowCount() { return examinations.size(); }

                @Override
                public List<Examination> getItemsByRange(int i, int i1) { return examinations.subList(i, i1); }

                @Override
                public Examination getItemByKey(Object key) 
                {
                    for (Examination e : examinations)
                        if (key.equals(getKey(e)))
                            return e;

                    return null;
                }

                @Override
                public Object getKey(Examination e) { return e.getId(); }
            });
        }
                
        return ExamsDataModel;
    }
    
    public void takePatSelection()
    {
        getSelectedPats().clear(); invalidExams();
        Iterator<Object> it = getSelectionPat().getKeys();
        
        while(it.hasNext())
        {
            Object obj = it.next();
            getPatsDataModel().setRowKey(obj);
            getSelectedPats().add((Patient) getPatsDataModel().getRowData());
        }
        
        //setto lo zoom in funzione della presenza delle cordinate del paziente
        Patient tmp = getSingleSelectedPat();
        if (tmp.getId() == -1 || tmp.getLatitudine() == 0.0F || tmp.getLongitudine() == 0.0F) gzoom = 1;
        else gzoom = DefGZoomCity;
    }
    
    public void takeExamSelection()
    {
        getSelectedExam().clear();
        Iterator<Object> it = getSelectionExam().getKeys();
        
        while(it.hasNext())
        {
            Object obj = it.next();
            getExaminationsDataModel().setRowKey(obj);
            getSelectedExam().add((Examination) getExaminationsDataModel().getRowData());
        }
    }
    
    public void updatePatient()
    {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PortaleVisitePU");
        EntityManager em = emf.createEntityManager();
        
        //associo a tmp il paziente selezionato nella collezzione al database
        Patient new_tmp, tmp = em.find(Patient.class, (new_tmp = getSingleSelectedPat()).getId());
        
        em.getTransaction().begin();
        
        //prelevo poi le nuove informazioni da quelle modificate sulla pagina
        tmp.setNome(new_tmp.getNome());
        tmp.setCognome(new_tmp.getCognome());
        tmp.setUsername(new_tmp.getUsername());
        tmp.setPassword(new_tmp.getPassword());
        tmp.setDataNascita(new_tmp.getDataNascita());
        tmp.setLuogoNascita(new_tmp.getLuogoNascita());
        tmp.setIndirizzo(new_tmp.getIndirizzo());
        tmp.setCap(new_tmp.getCap());
        tmp.setLongitudine(new_tmp.getLongitudine());
        tmp.setLatitudine(new_tmp.getLatitudine());
        
        //eseguo infine la transazione
        em.getTransaction().commit(); em.close();
    }
    
    public void updateExamination() 
    {
        //vedi metodo precedente
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PortaleVisitePU");
        EntityManager em = emf.createEntityManager();
        
        try
        {
            Examination new_tmp = getSingleSelectedExam();
            if (new_tmp.getId() != null)
            {
                Examination tmp = em.find(Examination.class, new_tmp.getId());
                em.getTransaction().begin();

                tmp.setTipo(new_tmp.getTipo());
                tmp.setScadenza(getNoTimeDate(new_tmp.getScadenza()));                
                tmp.setTipo_scadenza(new_tmp.getTipo_scadenza());
                tmp.setDescrizione(new_tmp.getDescrizione());
                tmp.setEffettuata(new_tmp.getEffettuata());

                em.getTransaction().commit(); em.close();
                
                if (new_tmp.getEffettuata()) genPDF(getSingleSelectedExam());
                
            }
        }
        catch(Exception ex) { }
    }
    
    public void newExamination()
    {
        Patient tmp_pat = null;
        if ((tmp_pat = getSingleSelectedPat()).getId() != -1)
        {
            EntityManagerFactory emf = Persistence.createEntityManagerFactory("PortaleVisitePU");
            EntityManager em = emf.createEntityManager();
            
            Examination max_id;
            try
            {
                //trovo la visita con id più alto per calcolarne il successivo
                max_id = em.createNamedQuery("Examination.findMaxId", Examination.class).getSingleResult();
            } //nel caso di nessuna visita presente imposto il nuovo id a (0+1)=1
            catch(Exception ex) { max_id = new Examination(); max_id.setId(0); }
            
            //creo la nuova visita vergine
            Examination new_ex = new Examination(max_id.getId() + 1, tmp_pat.getId(), "1", 
                                getToday(), "1", false, null);
            
            if (em.find(Examination.class, new_ex.getId()) == null)
            {
                //inserisco la nuova visita nel database
                em.getTransaction().begin();
                em.persist(new_ex);
                em.getTransaction().commit();
                em.close();
                
                invalidExams(); getSelectedExam().add(new_ex);
                
                //imposto il filtro per visualizzare le visite non effettuate così da rendere la nuova visita in evidenza
                //nella tabella
                setPerformedF(false);
            }
        }
    }
    
    public void deleteExamination()
    {
        Examination tmp = null;
        if ((tmp = getSingleSelectedExam()).getId() != null)
        {
            EntityManagerFactory emf = Persistence.createEntityManagerFactory("PortaleVisitePU");
            EntityManager em = emf.createEntityManager();
            
            if ((tmp = em.find(Examination.class, tmp.getId())) != null)
            {
                em.getTransaction().begin();
                em.remove(tmp);
                em.getTransaction().commit();
                em.close();
                
                invalidExams();
            }
        }
    }
    
    public void invalidPats()
    { patients = null; PatsDataModel = null; invalidExams(); }
    
    public void invalidExams()
    { ExamsDataModel = null; examinations = null; }
    
    public void invalidPatsQueue()
    {
        if (selectedPats != null) selectedPats.clear(); 
        if (selectionPat != null) selectionPat.clear(); 
        
        invalidExamsQueue();
    }
    
    public void invalidExamsQueue()
    {
        if (selectedExam != null) selectedExam.clear(); 
        if (selectionExam != null) selectionExam.clear();
    }
    
    public String getPatientFromExam(Examination exam)
    {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PortaleVisitePU");
        EntityManager em = emf.createEntityManager();
        
        Patient tmp = null;
        
        try
        {
            tmp = (Patient)em.createNamedQuery("Patient.findById", Patient.class).setParameter("id", exam.getId_pat())
                    .getSingleResult();
            if (tmp != null) return tmp.getCognome() + " " + tmp.getNome(); else return "";
        }catch(Exception ex) { return ""; }        
    }
    
    @Override
    public List<Patient> getPatientsList()
    { return (patients = super.getPatientsList()); }
    
    @Override
    public List<Patient> getWaitedPatientsList()
    { return (patients = super.getWaitedPatientsList()); }
    
    public Integer getWaitedPatientCount(Patient p)
    { 
        //restituisco il numero di richiami effettuati per il paziente
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PortaleVisitePU");
        EntityManager em = emf.createEntityManager();

        Integer count = -1;
        try
        {
            count = ((Number)em.createNamedQuery("Medic.findOwnWaitingPatientCount").setParameter("id", getId())
                    .setParameter("pid", p.getId()).getSingleResult()).intValue();
        }
        catch(Exception ex) { count = -1; }
        
        return count;
    }
    
    public Boolean getMoreCountedPat(Patient p)
    { return getWaitedPatientCount(p) > 1; }
    
    public void downloadContent()
    {
        Patient selP = getSingleSelectedPat();
        List<Float> coords = new GeonameWS().getCoordsContent(selP.getLuogoNascita());
        
        if (validateCoords(coords.get(0))) selP.setLatitudine(coords.get(0));
        if (validateCoords(coords.get(1))) selP.setLongitudine(coords.get(1));
        
        gzoom = DefGZoomCity;
    }
    
    private Boolean validateCoords(Float val)
    {
        return val != null && val >= -90.0 && val <= 90.0;
    }

    public int getGzoom() {
        return gzoom;
    }

    public void setGzoom(int gzoom) {
        this.gzoom = gzoom;
    }
    
    public void setContextPdfPat(String value)
    {
        contPdfPath = value;
    }
    
    private String getEmailFromPat(Patient pat)
    {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("PortaleVisitePU");
        EntityManager em = emf.createEntityManager();
        
        try
        {
            Referenze tmp = (Referenze)em.createNamedQuery("Referenze.findByIdPaz").setParameter("idPaz", pat.getId())
                    .getSingleResult();
            
            return tmp.getEmail();
        }catch (Exception ex){ return null; }
    }
    
    private void genPDF(Examination exam)
    {
        Patient pt = getSingleSelectedPat();
        
        Document doc = new Document(PageSize.A4);
        Font baseF = FontFactory.getFont(FontFactory.HELVETICA, 10);
        
        try {
            
            Patient pat = getSingleSelectedPat();
            String name = getId().toString() + "." 
                    + (new Integer(new File(contPdfPath).list().length + 1)).toString() + "_"
                    + getStringDate(exam.getScadenza()) + "_" + pat.getCognome() + "." + pat.getNome() + ".pdf",
                   path = contPdfPath + "/" + name;
            
            PdfWriter.getInstance(doc, new FileOutputStream(path , false));
            
            doc.open();
            
            Paragraph p1 = new Paragraph(new Chunk("Gentile Sig. " + pt.getCognome() + " " + pt.getNome() + ",\n", baseF)),
                      p2 = new Paragraph(new Chunk("viene qui riportata la sua anamnesi per la visita effettuata in data "
                              + getStringDate(exam.getScadenza()) + ":")),
                      p3 = new Paragraph(new Chunk(exam.getDescrizione())),
                      p4 = new Paragraph(new Chunk("Cordiali saluti\n" + getCognome() + " " + getNome()));
            
            p4.setAlignment(2);
                     
            doc.add(p1);
            doc.add(p2);
            doc.add(p3);
            doc.add(p4);
            
            doc.close();
            
            String email = getEmailFromPat(pt);
            
            if (email != null)
                new Sender().sendPdfLink(name, email);
            
        } catch (Exception ex) { }
        finally
        { doc.close(); }
    }
    
    private String getStringDate(Date d)
    {
        Calendar cal = Calendar.getInstance(); cal.setTime(d);        
        return getStringDate(cal);
    }
    private String getStringDate(Calendar cal)
    {
        //restituisce una stringa con la data nel formato gg-mm-yyyy
        return cal.get(Calendar.DAY_OF_YEAR) + "-" + (cal.get(Calendar.MONTH) + 1) + "-" + cal.get(Calendar.YEAR);
    }
}
